/*******************************************************************************
 * Copyright（C） CETC-32
 * @file:URLPermissions.java
 * @Description：
 * @Author ：徐文远
 * @version：1.0
 * @date ： 2021/4/22 下午8:30
 ******************************************************************************/

package com.cetc32.webutil.client.bean;
/****************************************************************
 * @Author xuwenyuan
 * @Date 2021.4.22
 * @Description 当前系统的URL权限集合
 * **************************************************************/
import com.cetc32.webutil.client.scanner.AnnotationClassScanner;
import com.cetc32.webutil.common.annotations.AccessPermission;
import com.cetc32.webutil.common.bean.LoginUser;
import com.cetc32.webutil.exception.S32Exception;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

@Component
@Scope("singleton")
public class URLPermissions {
    Logger logger = LoggerFactory.getLogger(URLPermissions.class);
    SSOProperties ssoProperties;

    /**
     * 权限集合，包含本系统所有权限标识及其对应访问URL集合
     * */

    HashMap<String,AccessRule> accessRules=new HashMap<>();
    public URLPermissions(){

    }

    public SSOProperties getSsoProperties() {
        return ssoProperties;
    }
    @Autowired
    public void setSsoProperties(SSOProperties ssoProperties) {
        this.ssoProperties = ssoProperties;
        setAccessRules(ssoProperties.getPermission());
    }
    /**
     * @param rules  内容格式如下
     *               SYSCODE^code1@/url1,/url2/*,/url3;code2@/url4,/url5,/url6/**;code!/url1/b/c,/url2/c/d/*
     * @Description rules中的内容进行接卸，首先根据分割拆分
     * */
    //@Value("${sso.permission}")
    private void setAccessRules(String rules) {
        if(StringUtils.isBlank(rules)){
            AnnotationClassScanner sanner =new AnnotationClassScanner();
            /**
             *该部分后继续考虑将在MyContextListener里实现，等容器加载完成后将权限信息维护到数据库
            Set<Class<?>> cl= sanner.getAnnotationClasses("",AccessPermission.class);
            Iterator<Class<?>>it =cl.iterator();
            while(it.hasNext()){
                Class t = it.next();
                AccessPermission ant = (AccessPermission)t.getDeclaredAnnotation(AccessPermission.class);
                ant.permission()
                //AccessPermission ant =t.getDeclaredAnnotation(AccessPermission.class);
            }**/
            if(!sanner.hasAnnotationClasses(AccessPermission.class)){
                throw new S32Exception("This Project is not use web-util‘s annotation , " +
                        "place holder ${sso.permission} is needed.");
            }else{
                if(null == ssoProperties.getSyscode()){
                    throw new S32Exception("This Project is not use web-util‘s annotation , " +
                            "place holder ${sso.syscode} is needed.");
                }
            }
            return;
        }
        if( (!rules.contains("^"))
                || (!rules.contains("@"))
                || (!rules.startsWith("S"))){
            throw new S32Exception("Can Not Match properites ${sso.permission}.");
        }
        /** 根据分号分隔符进行切分，切分后获得对应权限码及其对应的url访问控制项目及类型 */
        String[] ps0 = rules.split("\\^");
        String syscode = ps0[0];
        String[] ps = ps0[1].split(";");
        for(String s:ps){/**遍历切分后的权限信息*/
            AccessRule ar=null;
            if(s.contains("@")){/**解析@分割符划分的权限信息，并创建权限对象**/
                ar = AccessRule.addAccessRule(syscode,s);
            }else if(s.contains("!")){/**解析！分割符划分的权限信息，并创建权限对象**/
                ar = AccessRule.addDeniesRule(syscode,s);
            }
            if(null != ar){/**如果成功获取到AccessRulez则将此保存到权限集合Set*/
                if(accessRules.containsKey(ar.getCode())){/**若已包含对应权限，则把得到权限追加到权限记录中**/
                    accessRules.get(ar.getCode()).addPermission(ar);
                }else{/**若不存在同名权限直接添加到集合**/
                    accessRules.put(ar.getCode(),ar);
                }
            }
        }
    }
    /***
     * 根据登录用户及请求URL校验当前用户是否有访问权限,如果accessRule为空则认为是允许访问
     * @param loginUser 登录用户
     * @param url 当前访问url
     * @return true 表示允许访问，false 不允许访问
     * **/
    public boolean hasPermission(LoginUser loginUser, String url){
        /**accessRule为空则认为是允许访问，避免未添加规则的url被限制访问**/
        if(accessRules == null || accessRules.size()==0)
            return true;
        List<String> list=loginUser.getPermissions();
        for(String code :list){
            logger.debug("{} hasPermiison Code: {}",url,code);
            if(accessRules.containsKey(code)){
                AccessRule rule=accessRules.get(code);
                return rule.hasPermission(url);
            }
        }
        /**accessRules不为空，且又找不到对应匹配规则则认为不允许访问**/
        return false;
    }

    /***
     * 获取重新整合后的权限码集合
     * @return 集合
     * **/
    public Set<String> getCode(){
        return accessRules.keySet();
    }
}
